package com.biao.java8.demo;

import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
import java.util.stream.LongStream;

// 使用forkJoin 必须继承RecursiveTask
public class ForkJoinCalculate extends RecursiveTask<Long> {

    private static final long serialVersionUID = 21313123123l;

    private long start;
    private long end;

    private static final long THRESHOLD = 10000;

    public ForkJoinCalculate(long start, long end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected Long compute() {  // 重写RecursiveTask 的方法
        long length = end - start;
        if (length <= THRESHOLD) {
            long sum = 0;
            for (long i = start; i <= end; i++) {
                sum += i;
            }
            return sum;
        } else {
            long middle = (start + end) / 2;
            ForkJoinCalculate left = new ForkJoinCalculate(start, middle);
            left.fork();        // 拆分子任务

            ForkJoinCalculate right = new ForkJoinCalculate(middle + 1, end);
            right.fork();       // 拆分子任务

            return left.join() + right.join();
        }
    }

    public static void main(String[] args) {
        Instant start = Instant.now();      // 通过这种方式获取的时间戳与北京时间相差8个时区
        // 需要修正为北京时间:   Instant.now().plusMillis(TimeUnit.HOURS.toMillis(8));

        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ForkJoinTask<Long> forkJoinTask = new ForkJoinCalculate(0, 1000000000L);      // 数值越大,效果越明显
        Long sum = forkJoinPool.invoke(forkJoinTask);
        System.out.println(sum);

        Instant end = Instant.now();
        System.out.println("ForkJoin使用了" + Duration.between(start, end).toMillis() + "毫秒");

        Instant start2 = Instant.now();
        Long sum2 = 0l;
        for (int i = 0; i <= 1000000000L; i++) {
            sum2 += i;
        }
        System.out.println(sum2);
        Instant end2 = Instant.now();
        System.out.println("普通for循环使用了" + Duration.between(start2, end2).toMillis() + "毫秒");


        // 推荐使用
        Instant start3 = Instant.now();
        LongStream.rangeClosed(0, 1000000000L)
                .parallel()     // 底层用的还是ForkJoin,人家封装的应该更好一点
                .reduce(0, Long::sum);
        Instant end3 = Instant.now();
        System.out.println("java8的并行流使用了" + Duration.between(start3, end3).toMillis() + "毫秒");


    }
}
